﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Common;
using SdmxMl.Manager;
using SdmxMl.Panels;
using SdmxMl.Structure;

namespace SdmxMl.UC
{
    /// <summary>
    /// User controls grouping Dimension detail edition
    /// </summary>
    public partial class UcEditDimension : UserControl
    {
        #region Internal Members

        private BaseDimensionType bd;
        private BaseDimensionTypeList bdList;
        private UcTextFormat ucTextFormat = null;
        private DataGridView dataGridView;
        private bool _isFinal;

        #endregion //Internal Members

        #region Construction

        public UcEditDimension()
        {
            InitializeComponent();
            ucTextFormat = new UcTextFormat();
            customComboBoxTextType.DropDownControl = ucTextFormat;

            comboBoxCrossAttach.Items.Clear();
            foreach (CrossSectionalAttachKind cross in Enum.GetValues(typeof(CrossSectionalAttachKind)))
                comboBoxCrossAttach.Items.Add(cross.ToString());

            comboBoxAttachLevel.Items.Clear();
            foreach (AttributeType.AttachmentLevelType al in Enum.GetValues(typeof(AttributeType.AttachmentLevelType)))
                comboBoxAttachLevel.Items.Add(al.ToString());

            comboBoxAssignStatus.Items.Clear();
            foreach (AttributeType.AssignmentStatusType al in Enum.GetValues(typeof(AttributeType.AssignmentStatusType)))
                comboBoxAssignStatus.Items.Add(al.ToString());
            
            ucCodelistRef1.CodelistSelect += new EventHandler(ucCodelistRef1_CodelistSelect);

            ucConceptRef1.ConceptSelect += new EventHandler(ucConceptRef1_ConceptSelect);
        }

        #endregion //Construction

        #region Binding

        public void BindFromList(BaseDimensionTypeList bl, DataGridView dgv, BaseDimensionType rowBd, bool isFinal)
        {
            _isFinal = isFinal;
            dataGridView = dgv;
            bdList = bl; bd = null;

            // Editable or not
            ucConceptRef1.IsFinal = _isFinal;
            ucCodelistRef1.IsFinal = _isFinal;
            if (ucTextFormat.TF != null)
                ucTextFormat.IsFinal = isFinal;
            comboBoxRole.Enabled = isFinal == false;
            comboBoxCrossAttach.Enabled = isFinal == false;
            comboBoxAssignStatus.Enabled = isFinal == false;
            comboBoxAttachLevel.Enabled = isFinal == false;
            ucDualList.IsFinal = isFinal;

            //Slightly changes controls according to edited type
            comboBoxRole.Items.Clear();
            if (bdList is AttributeTypeList)
            {
                foreach (AttributeType.AttributeKindType k in Enum.GetValues(typeof(AttributeType.AttributeKindType)))
                    comboBoxRole.Items.Add(k.ToString());
            }
            else if (bdList is DimensionTypeList)
            {
                foreach (DimensionType.DimensionKind k in Enum.GetValues(typeof(DimensionType.DimensionKind)))
                    if (k != DimensionType.DimensionKind.PrimaryMeasure)
                    comboBoxRole.Items.Add(k.ToString());
            }

            labelRole.Visible = comboBoxRole.Items.Count > 0;
            comboBoxRole.Visible = comboBoxRole.Items.Count > 0;

            bool hasCrossAttach = bdList is DimensionTypeList || bdList is AttributeTypeList;
            labelCrossAttach.Visible = hasCrossAttach;
            comboBoxCrossAttach.Visible = hasCrossAttach;

            panelAttrib.Visible = bdList is AttributeTypeList;
            if (bdList != null && bdList.Count > 0)
            {
                int index = 0;
                if (rowBd != null)
                    index = Math.Max(0, bdList.IndexOf(rowBd));
                BindRow(bdList[index]);
            }

        }

        public void UpdateAttributeObservation(BaseDimensionType bdt)
        {
            // Update previous Attribute of observation from dualList if needed
            if (bdt != null)
            {
                AttributeType at = bdt as AttributeType;
                if (at != null && (at.AttachmentLevel == AttributeType.AttachmentLevelType.Observation))
                {
                    at.AttachmentMeasureList.Clear();
                    foreach (string s in ucDualList.ListAssigned.Items)
                        at.AttachmentMeasureList.Add(s);
                }
            }
        }

        /// <summary>
        /// Binds selected datagrid row equivalent dimension to edit controls.
        /// </summary>
        /// <param name="rowBd">the dimension to bind to controls</param>
        public void BindRow(BaseDimensionType rowBd)
        {
            if (bd != rowBd)
            {
                // Update previous Attribute of observation from dualList if needed
                UpdateAttributeObservation(bd);

                // Refresh to new dimension to edit
                bd = rowBd;
                if (bd != null)
                {
                    textBoxId.Text = bd.Id;
                    ucCodelistRef1.BindRef(bd.CodelistInfo);
                    ucConceptRef1.BindRef(bd.ConceptSchemeInfo, bd.ConceptInfo);

                    customComboBoxTextType.Text = bd.TextFormat.ToString();
                    ucTextFormat.TF = bd.TextFormat;

                    DimensionType dim = bd as DimensionType;
                    if (dim != null)
                        comboBoxRole.SelectedIndex = (int)dim.DimKind;
                    else if (bd is TimeDimensionType)
                        comboBoxRole.SelectedIndex = (int)DimensionType.DimensionKind.TimeDimension;

                    TimeDimensionType tim = bd as TimeDimensionType;
                    if (tim != null)
                        comboBoxCrossAttach.SelectedIndex = (int)tim.CrossSectionalAttach;

                    UpdateAttach(bd);
                }
            }
        }
        // Manage Edition possibility
        private void IsFinalEditControls(bool isFinal)
        {
            bool enabled = isFinal == false;
            comboBoxRole.Enabled = enabled;
            comboBoxCrossAttach.Enabled = enabled;
            textBoxId.Enabled = enabled;
        }

        /// <summary> Binding Attribute attachement </summary>
        /// <param name="bd">the dimension in edition </param>
        private void UpdateAttach(BaseDimensionType bd)
        {
            try
            {
                AttributeType at = bd as AttributeType;
                if (at != null)
                {
                    comboBoxAttachLevel.SelectedIndex = (int)at.AttachmentLevel;
                    comboBoxAssignStatus.SelectedIndex = (int)at.AssignmentStatus;
                    comboBoxRole.SelectedIndex = (int)at.AttributeKind;
                    comboBoxCrossAttach.SelectedIndex = (int)at.CrossSectionalAttach;

                    KeyFamilyType dsd = bdList.ParentDsd;

                    // Fill lists
                    ucDualList.ListAssigned.Items.Clear();
                    ucDualList.ListAssigned.Sorted = false;
                    ucDualList.ListAvailable.Items.Clear();
                    ucDualList.ListAvailable.Sorted = false;

                    // Create list of AttributeRelationship, for sdmx 2.1.
                    ucDualListRelationship.ListAssigned.Items.Clear();
                    ucDualListRelationship.ListAssigned.Sorted = false;
                    ucDualListRelationship.ListAvailable.Items.Clear();
                    ucDualListRelationship.ListAvailable.Sorted = false;
                    if (at.AttachmentLevel != AttributeType.AttachmentLevelType.Observation)
                    {
                        ucDualListRelationship.Enabled = true;
                        List<string> listRel = new List<string>();
                        List<string> listAvailRel = new List<string>();
                        foreach (BaseDimensionType dim in dsd.DimensionList)
                        {
                            if (dim is DimensionType)
                            {
                                listAvailRel.Add(dim.ConceptInfo.Id);
                            }
                        }

                        listRel.AddRange(listAvailRel);

                        foreach (string s in listRel)
                        {
                            if (at.AttributeRelationship.Contains(s))
                            {
                                ucDualListRelationship.ListAssigned.Items.Add(s);
                                listAvailRel.Remove(s);
                            }
                        }

                        foreach (string sa in listAvailRel)
                            ucDualListRelationship.ListAvailable.Items.Add(sa);
                    }

                    // Create list of groups, for the one selected, initialise duallist.
                    if (at.AttachmentLevel == AttributeType.AttachmentLevelType.Group)
                    {
                        ucDualList.Enabled = true;
                        GroupTypeList gtl = new GroupTypeList(dsd);
                        gtl.AddRange(dsd.GroupList);
                        foreach (GroupType gr in dsd.GroupList)
                        {
                            if (at.AttachmentGroupList.Contains(gr.Id))
                            {
                                ucDualList.ListAssigned.Items.Add(gr.Id);
                                gtl.Remove(gr);
                            }
                        }

                        foreach (GroupType g in gtl)
                            ucDualList.ListAvailable.Items.Add(g.Id);

                    }

                    else if (at.AttachmentLevel == AttributeType.AttachmentLevelType.Observation)
                    {
                        if (dsd.HasMeasureDimension)
                        {
                            /*
                            CodeListType cl = ReferenceManager.LocateCodelist(dsd.MeasureDimension.CodelistInfo);
                            if (cl == null)
                                MessageBox.Show(this, "Unable to locate Codelist of the Measure", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                             
                            else
                             * * */
                            {
                                CrossSectionalMeasureTypeList csml = new CrossSectionalMeasureTypeList(dsd);
                                csml.AddRange(dsd.CrossSectionalMeasureList.ToArray());
                                csml.Remove(dsd.CrossSectionalMeasureList.PrimaryMeasure);
                                ucDualList.Enabled = true;
                                CrossSectionalMeasureTypeList csmlAvailable = new CrossSectionalMeasureTypeList(dsd);
                                csmlAvailable.AddRange(csml.ToArray());

                               // CodeList cList = new CodeList();
                               // cList.AddRange(cl.CodeList);
                                foreach (BaseDimensionType meas in csml)
                                {
                                    if (at.AttachmentMeasureList.Contains(meas.ConceptInfo.Id))
                                    {
                                        ucDualList.ListAssigned.Items.Add(meas.ConceptInfo.Id);
                                        csmlAvailable.Remove(meas);
                                    }
                                }

                                foreach (BaseDimensionType meas in csmlAvailable)
                                    ucDualList.ListAvailable.Items.Add(meas.ConceptInfo.Id);
                            }
                        }
                    }
                    else
                    {
                        ucDualList.Enabled = false;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "DSD", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion //Binding

        #region Controls Event

        private void customComboBoxTextType_DropDownClosed(object sender, EventArgs e)
        {
            if (bd != null)
            {
                customComboBoxTextType.Text = bd.TextFormat.TextType.ToString();
                UpdateRow();
            }
        }
        
        private void ucCodelistRef1_CodelistSelect(object sender, EventArgs e)
        {
            if (bd != null)
                UpdateRow();
        }

        void ucConceptRef1_ConceptSelect(object sender, EventArgs e)
        {
            if (bd != null)
            {
                UpdateRow();
                textBoxId.Text = ucConceptRef1.ConceptId;
            }
        }

        private void comboBoxRole_SelectedIndexChanged(object sender, EventArgs e)
        {
             DimensionType dim = bd as DimensionType;
             AttributeType at = bd as AttributeType;

            // Only time dimension can have Time Dimension role. Ans only one can exists
            if (comboBoxRole.SelectedIndex == (int)DimensionType.DimensionKind.TimeDimension &&
                at == null && dim != null)
            {
                MessageBox.Show("Reserved to unique Time Dimension", "DSD", MessageBoxButtons.OK, MessageBoxIcon.Error);
                // restore
                comboBoxRole.SelectedIndex = (int)dim.DimKind;
            }

            if (dim != null)
                dim.DimKind = (DimensionType.DimensionKind)comboBoxRole.SelectedIndex;
            if (at != null)
                at.AttributeKind = (AttributeType.AttributeKindType)comboBoxRole.SelectedIndex;

            UpdateRow();
        }

        private void comboBoxCrossAttach_SelectedIndexChanged(object sender, EventArgs e)
        {
            // OK for time and normal Dimension that derive from TimeDim.
            TimeDimensionType tim = bd as TimeDimensionType;
            if (tim != null)
            {
                tim.CrossSectionalAttach = (CrossSectionalAttachKind)comboBoxCrossAttach.SelectedIndex;
                UpdateRow();
            }
            else
            {
                // Also for attributes
                AttributeType at = bd as AttributeType;
                if (at != null)
                {
                    at.CrossSectionalAttach = (CrossSectionalAttachKind)comboBoxCrossAttach.SelectedIndex;
                    UpdateRow();
                }
            }
        }

        private void comboBoxAssignStatus_SelectedIndexChanged(object sender, EventArgs e)
        {
            AttributeType at = bd as AttributeType;
            if (at != null)
            {
                at.AssignmentStatus = (AttributeType.AssignmentStatusType)comboBoxAssignStatus.SelectedIndex;
                UpdateRow();
            }
       }

        private void comboBoxAttachLevel_SelectedIndexChanged(object sender, EventArgs e)
        {
            AttributeType at = bd as AttributeType;
            if (at != null)
            {
                at.AttachmentLevel = (AttributeType.AttachmentLevelType)comboBoxAttachLevel.SelectedIndex;
                UpdateAttach(bd);
                UpdateRow();
            }
        }

        /// <summary> Reflects change in datagrid row. </summary>
        public void UpdateRow()
        {
            if (bd != null)
            {
                bd.TextFormat = ucTextFormat.TF;
                bd.Id = textBoxId.Text;
                DataTable tb = dataGridView.DataSource as DataTable;
                dataGridView.EndEdit();
                int rowIndex = bdList.IndexOf(bd);
                if (rowIndex >= 0 && tb != null)
                {
                    if (tb.Rows.Count <= rowIndex)
                    {
                    }
                    else
                    {
                        // Update row
                        tb.Rows[rowIndex].AcceptChanges();
                        tb.Rows[rowIndex].ItemArray = bdList.GetRowObjects(bdList[rowIndex]).ToArray();
                        tb.Rows[rowIndex].AcceptChanges();
                    }
                }
            }
            UpdateAttributeObservation(bd);
        }

        #endregion //Controls Event

    }
}
